(function (f) {
	var a = {errorRequired:"\u6b64\u9879\u4e3a\u5fc5\u586b\u9879", errorTempl:"<span class=\"validate-error\">{msg}</span>", optionTempl:"<span class=\"validate-option\">{msg}</span>", callback:null}, c = ".input", b = ".validate-error", e = ".validate-option", d = function (i, h, k, g, j) {
		if (!h || !i) {
			return;
		}
		this.asyncList = [];
		this.asyncEndHandle = null;
		this._init(i, h, k, g, j);
	};
	d.prototype = {_init:function (i, h, l, g, k) {
		var j;
		j = this.node = f(i);
		this.form = (j.attr("tagName").toLowerCase() === "form") ? j : j.find("form");
		this.config = f.extend(a, k);
		this.rules = h;
		this.errorMsg = l || {};
		this.optionMsg = g || {};
		j.data("validateForm", this);
		this._bindEvent();
	}, _bindEvent:function () {
		if (this.node.data("hasBindValidateEvent")) {
			return;
		}
		this.node.data("hasBindValidateEvent", true);
		this.form.submit(f.proxy(function (g) {
			this.validate();
			this._handleFormSubmit(g);
		}, this)).find("input, select, textarea").bind({blur:f.proxy(function (g) {
			this._handleBlur(g);
		}, this), focus:f.proxy(function (g) {
			this._handleFocus(g);
		}, this)});
		this._bindRules();
	}, _bindRules:function () {
		var h = this.rules, g;
		for (g in h) {
			if (h.hasOwnProperty(g)) {
				f(h[g].elems, this.form).each(function (k, m) {
					var j = f(m), l = j.data("validate-rules") || "";
					j.data("validate-rules", l + "," + g);
				});
			}
		}
	}, _handleBlur:function (n) {
		var h = f(n.target), o = h.parents(c), l, g, m, j, p = false, q = h.data("validate-rules");
		o.find(e).hide();
		if (!q) {
			return;
		}
		q = q.split(",").slice(1);
		for (l = 0, m = q.length; l < m; l++) {
			g = this.rules[q[l]];
			this.validate(g, this.errorMsg[q[l]], h);
		}
	}, _handleFocus:function (h) {
		var g = h.target.getAttribute("name"), i;
		if (!g) {
			return;
		}
		if (i = this.optionMsg[g.toLowerCase()]) {
			this.displayOptionMsg(f(h.target), i);
		}
	}, _handleFormSubmit:function (i) {
		var h, g, j = this;
		h = this.form.find(".has-error");
		if (h.length > 0) {
			i.preventDefault();
			f(j.form).trigger("hasError");
			return;
		}
		g = this.form.find(".has-process");
		if (g.length > 0) {
			i.preventDefault();
			this.asyncEndHandle = function () {
				j.asyncEndHandle = null;
				j._handleFormSubmit(i);
			};
			return;
		}
		if (j.config.callback) {
			j.config.callback(j.form);
		} else {
			//IE下造成重复提交
			//j.form[0].submit();
		}
	}, clearErrorMsg:function (g) {
		var h = g.parents(c);
		h.find(b).hide();
	}, displayError:function (i, k) {
		var j = i.parents(c), h = j.find(e), g = j.find(b);
		h.hide();
		if (g.length === 0) {
			f(this.config.errorTempl.replace("{msg}", k)).appendTo(j).show();
			return;
		}
		g.show().html(k);
		return;
	}, displayOptionMsg:function (i, k) {
		if (!k) {
			return;
		}
		var j = i.parents(c), h = j.find(e), g = j.hasClass("has-error");
		if (g) {
			return;
		}
		if (h.length === 0) {
			f(this.config.optionTempl.replace("{msg}", k)).appendTo(j).show();
			return;
		}
		h.show().html(k);
		return;
	}, asyncValidate:function (i, h, g) {
		if (!i || !h) {
			return;
		}
		var j = i.parent();
		if (j.hasClass("has-process")) {
			return;
		}
		j.addClass("has-process");
		this.asyncList.push(f.getJSON(h, f.proxy(function (k) {
			var l = this.asyncList;
			g && g(k);
			j.removeClass("has-process");
			this.asyncList.pop();
			if (l.length === 0) {
				this.asyncEndHandle && this.asyncEndHandle();
			}
		}, this)));
		f("body").ajaxError(function () {
			alert("远程验证失败!");
		});
	}, validate:function (m, l, h) {
		var i = this.errorMsg.errorRequired, n = function (v, x, t, w) {
			var u = t.parents(c), q = false, s;
			if (v.isRequired && f.trim(t.val()) === "") {
				w.displayError(t, i || a.errorRequired);
				q = true;
				u.addClass("has-error");
			} else {
				for (s in v) {
					if (v.hasOwnProperty(s) && typeof v[s] === "function") {
						if (v[s](t, w)) {
							w.displayError(t, x[s]);
							u.addClass("has-error");
							q = true;
							break;
						}
					}
				}
				if (!q) {
					w.clearErrorMsg(t);
					u.removeClass("has-error");
				}
			}
		}, g, p, o, j;
		if (!m) {
			p = this.rules;
			o = this.errorMsg;
			for (j in p) {
				if (p.hasOwnProperty(j)) {
					g = p[j];
					f(g.elems, this.form).each(f.proxy(function (k, q) {
						n(g, o[j], f(q), this);
					}, this));
				}
			}
		} else {
			n(m, l, h, this);
		}
	}};
	f.extend({validate:{isEmail:function (g) {
		return /^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/.test(g);
	}}});
	f.fn.validateForm = function (j, l, i, k) {
		var h = i, g = k;
		if (arguments.length === 3) {
			h = null;
			g = i;
		}
		this.each(function () {
			new d(this, j, l, h, g);
		});
		return this;
	};
})(jQuery);

